/*
 * Class representing a loan of a book by a subscriber
 * @author M.T. Segarra
 * @version 0.0.1
 */
package loansManagement;


import java.io.Serializable;
import java.util.*;

import javax.persistence.*;

import main.Constraints;
import exceptions.*;
import subscribersManagement.Subscriber;
import booksManagement.*;
//import jpaUtils.JPAUtil;

/**
 * @author        user
 */
@Entity
//@IdClass(LoanPK.class)*/
@Table(name="loans")
@NamedQuery(name="findAllLoans", query="select l from Loan l")
@PrimaryKeyJoinColumn(name="loan_id")
public class Loan implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	/**
   * @uml.property  name="status"
   * @uml.associationEnd  
   */
	@Enumerated(EnumType.STRING)
	private LoanStatus status;
	
	/**
   * @uml.property  name="id"
   */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;
	
	/*/**
   * @return
   * @uml.property  name="id"
   */
	/*public long getId(){
  	return id;
  }
	
	/**
   * @param  id
   * @uml.property  name="id"
   */
	/*public void setId(long id){
  	this.id = id;
  }*/
	
	/*@EmbeddedId
	private LoanPK loanPK;*/
	@Column(name= "returned_date")
	private Calendar returnedDate;
	/**
   * @uml.property  name="returnDate"
   */
	@Column(name="return_date")
	private Calendar returnDate;
	
	/**
	 * This function return true if the copy loaned is a book
	 * and false otherwise
	 * @return
	 */
	public boolean isABook(){
		Media media = copy.getMedia();
		return media instanceof Book;
	}
	
	
	/**
	 * This function return true if the copy loaned is a dvd
	 * and false otherwise
	 * @return
	 */
	public boolean isADVD(){
		Media media = copy.getMedia();
		return media instanceof DVD;
	}

	/**
   * Getter of the property <tt>returnDate</tt>
   * @return        Returns the returnDate.
   * @uml.property  name="returnDate"
   */
	public Calendar getReturnDate() {
  	return returnDate;
  }

	/**
   * Setter of the property <tt>returnDate</tt>
   * @param returnDate        The returnDate to set.
   * @uml.property  name="returnDate"
   */
	public void setReturnDate(Calendar returnDate) {
  	this.returnDate = returnDate;
  }
	/**
   * date when the copy was loaned
   * @uml.property  name="loanDate"
   */
	@Column(name="loan_date")
	private Calendar loanDate;
	
	/**
   * @return
   * @uml.property  name="loanDate"
   */
	public Calendar getLoanDate(){
  	return this.loanDate;
  }
	
	/**
   * @param  loanDate
   * @uml.property  name="loanDate"
   */
	public void setLoanDate(Calendar loanDate){
  	this.loanDate = loanDate;
  }

	/**
   * @uml.property  name="copy"
   * @uml.associationEnd  
   */
	//@Id
	//@PrimaryKeyJoinColumn(name = "copy_id")
	//@MapsId("copyId")
	@OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "copy_id")
  private Copy copy =
  null;

	/**
   * Getter of the property <tt>copy</tt>
   * @return        Returns the copy of the media.
   * @uml.property  name="copy"
   */
	public Copy getCopy() {
  	return copy;
  }

	/**
   * Setter of the property <tt>book</tt>
   * @param book        The book to set.
   * @uml.property  name="copy"
   */
	public void setCopy(Copy copy) {
  	this.copy = copy;
  }
	
	public Loan(){
		
	}

	/**
	 * Creates the loan of copy for lender
	 * Constraints checking is performed by the caller
	 * @param copy the copy to be lent
	 * @param lender the subscriber 
	 * @throws BadParametersException 
	 * @throws TooManyLoansException 
	 * @throws LentBookException 
	 * @throws ReservedCopyException 
	 */
	public Loan(Copy copy, Subscriber lender) throws BadParametersException, 
	TooManyLoansException, LentBookException, ReservedCopyException{
		if ((copy == null) || (lender == null))
			throw new BadParametersException();
		
		this.copy = copy;
		this.lender = lender;
		this.loanDate = new GregorianCalendar();
		Calendar rDate = new GregorianCalendar();
		rDate.add(Calendar.MONTH, Constraints.LOAN_DELAY);
		this.returnDate = rDate;
		
		// Update the subscriber if he can lend
		lender.lend(this);
		
		// Update the copy if not already lent
		copy.lend(this);
		
		this.setStatus(LoanStatus.LOANED);
	}

	/**
	 * Two loans are equal is they concern the same book
	 * the same lender and return date
	 * @return true if the current loan is the same as the parameter
	 */
	@Override
	public boolean equals(Object loan){
		if (loan == null)
			return false;
		Loan l = (Loan)loan;
		boolean res = this.copy.equals(l.copy) 
			&& this.lender.equals(l.lender) 
			&& (this.returnDate.equals(l.returnDate));
		return res;	
	}

		
	/**
	 * Called by the lent copy
	 * Clear all the information contained in this loan
	 * if the lender is ok
	 * @throws BadParametersException 
	 * @throws LentBookException 
	 */
	public void returnCopy() throws BadParametersException, 
	LentBookException{
				
		// Ask the lender to return the copy
		lender.returnCopy(this);
		// Clear lender, book, and return date
		returnDate = null;
		returnedDate = new GregorianCalendar();
		setStatus(LoanStatus.RETURNED);
	}


	/**
   * @uml.property  name="lender"
   * @uml.associationEnd  
   */
	@ManyToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "borrower_ref")
  private Subscriber lender =
  null;

	/**
   * Getter of the property <tt>lender</tt>
   * @return        Returns the lender.
   * @uml.property  name="lender"
   */
	public Subscriber getLender() {
  	return lender;
  }

	/**
   * Setter of the property <tt>lender</tt>
   * @param lender        The lender to set.
   * @uml.property  name="lender"
   */
	public void setLender(Subscriber lender) {
  	this.lender = lender;
  }
	
	@Override
	public String toString(){
		return "Subscriber : " + this.lender.getFirstName() + " " + this.lender.getLastName() + ", media : " + this.copy.getMedia().getTitle() + ", Copy n°" + this.copy.getNumber();
	}


	public LoanStatus getStatus()
  {
	  return status;
  }


	public void setStatus(LoanStatus status)
  {
	  this.status = status;
  }


}



//PK id copy + id suscriber + 
/*/**
 * @author  user
 */
/*@Embeddable
class LoanPK implements Serializable{
	private static final long serialVersionUID = 1L;

	private Calendar loanDate;
	private long copyId;

	public long getCopyId()
  {
  	return copyId;
  }
	public void setCopy(long copyId)
  {
  	this.copyId = copyId;
  }
	public void setLoanDate(Calendar loanDate)
  {
  	this.loanDate = loanDate;
  }

	public Calendar getLoanDate(){
		return loanDate;
	}
	public LoanPK(){
		
	}

	
	
}*/

